/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.openbookformat.heading;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.JOptionPane;
import org.openbookformat.chaptersviewer.OBFChaptersViewerTopComponent;
import org.openbookformat.obffinder.FindResult;
import org.openbookformat.obffinder.FindUtil;
import org.openbookformat.obffinder.filters.Filter;
import org.openbookformat.obffinder.filters.FindReplaceFilter;
import org.openbookformat.project.Chapter;
import org.openbookformat.project.HeadingPointer;
import org.openbookformat.tags.CompositeTag;
import org.openbookformat.tags.HeadingTag;
import org.openbookformat.tags.TagUtil;
import org.openide.cookies.EditorCookie;
import org.openide.loaders.DataObject;
import org.openide.nodes.Node;
import org.openide.util.lookup.ServiceProvider;

/**
 *
 * @author matamh0a
 */
@ServiceProvider(service=Filter.class)
public class FindHeadingsFilter extends FindReplaceFilter {    
    List<Chapter> chpts;
    
    public FindHeadingsFilter() {
        name = "Find Headings Filter";
        findText = "<custom_code>";
        replaceText = "<custom_code>";
        regExp = true;
        ignoreCase = false;
        useVariables = false;
        useIgonreNewLine = false;
        applyToAll = true;
        description = "Find Headings";
        chapters = new ArrayList<DataObject>();
        
        
    }
    
    @Override
    public Map<DataObject, ArrayList<FindResult>> find() {
        Map<DataObject, ArrayList<FindResult>> findResult
                = new HashMap<DataObject, ArrayList<FindResult>>();
        
        chpts = new ArrayList<Chapter>();
        Node[] nodes = OBFChaptersViewerTopComponent.getDefault().
                getExplorerManager().getRootContext().getChildren().getNodes();
        System.out.println("noedes.length:" + nodes.length );
        chpts = new ArrayList<Chapter>();
        for(int i = 0; i < nodes.length; i++)
            chpts.add(nodes[i].getLookup().lookup(Chapter.class));        
        
        //Initialize findResult
        for(int i = 0; i < chpts.size(); i++) {
            findResult.put(chapters.get(i), new ArrayList<FindResult>());
        }
        
        //Get selected headings,
        Node[] sNodes = null;
        sNodes = OBFHeadingsTopComponent.getInstance().
                getExplorerManager().getSelectedNodes();
        if(sNodes.length == 0) {
            JOptionPane.showMessageDialog(null, "Please select some headings.", 
                    "Heading Finder", JOptionPane.ERROR_MESSAGE);
            return findResult;
        }
        
        List<HeadingPointer> headings = OBFHeadingsTopComponent.getInstance().
                getBookProp().getHeadings();
            
        HeadingPointer pointer = null;
        HeadingPointerLocation ptrLocation = null;        
        FindUtil fu = null;
        EditorCookie ed = null;
        ArrayList<FindResult> r = new ArrayList<FindResult>();
        for(int i = 0; i < sNodes.length; i++) {
            pointer = sNodes[i].getLookup().lookup(HeadingPointer.class);
            
            //where to start searching
            ptrLocation = findPointerLocation(pointer, headings);
            
            //start searching ...
            String regexp = "\n\\s*(\\Q" + pointer.getHeading() + "\\E)\\s*([:]?)\\s*\n";
            String toc = null;
            for (int k = ptrLocation.getChapterIndex(); k < chapters.size(); k++) {             
                ed = chapters.get(k).getCookie(EditorCookie.class);
                
                fu = new FindUtil(regexp, 
                            "\n" + new HeadingTag(pointer.getLevel(), true, 
                            TagUtil.textTagToCompositeTag(pointer.getHeading())));
                fu.setRegExp(true);
                fu.setUseVariables(true);
                r = fu.find(ed);
                for(int j = 0; j < r.size(); j++) {
                    if(r.get(j).getVariable(1).length() > 0)
                        r.get(j).setReplace("\n" + new HeadingTag(
                                pointer.getLevel(), true,  
                                TagUtil.textTagToCompositeTag(
                                //r.get(j).getVariable(0) + r.get(j).getVariable(1)),
                                r.get(j).getFind().replace("\n", "").trim()),
                                TagUtil.textTagToCompositeTag(pointer.getHeading())));
                }
                if(!r.isEmpty()) {
                    pointer.setOffset(r.get(0).getIndex());
                    pointer.setChapter(chpts.get(k));
                    findResult.get(chapters.get(k)).add(r.get(0));
                    break;
                }
            }
        }        
        return findResult;
    }
    
    private HeadingPointerLocation findPointerLocation(HeadingPointer pointer,
            List<HeadingPointer> headings) {
        //go back till you find a valid offset.
        int ptrIdx = headings.indexOf(pointer);
        if(ptrIdx == 0) {
            return new HeadingPointerLocation(0, 0);
        }
        //check the prev pointer
        if(headings.get(ptrIdx - 1).getOffset() == -1) { //not valid
            return findPointerLocation(headings.get(ptrIdx - 1), headings);
        } else { //valid
            return new HeadingPointerLocation(headings.get(ptrIdx -1).getOffset(),
                    chpts.indexOf(headings.get(ptrIdx -1).getChapter()));
        }
    }
    
    private class HeadingPointerLocation {
        private int offset;
        private int chapterIndex;

        public HeadingPointerLocation(int offset, int chapterIndex) {
            this.offset = offset;
            this.chapterIndex = chapterIndex;
        }

        public int getChapterIndex() {
            return chapterIndex;
        }

        public void setChapterIndex(int chapterIndex) {
            this.chapterIndex = chapterIndex;
        }

        public int getOffset() {
            return offset;
        }

        public void setOffset(int offset) {
            this.offset = offset;
        }
        
    }

}
